package com.region.common.adapter.json.jackson;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.region.common.adapter.json.JSONAdapter;
import com.region.common.adapter.json.JSONAdapterFactory;
import com.region.common.adapter.json.convert.JsonConvertor;
import com.region.common.exception.JsonAdapterException;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * @author liujeiyu
 * @date 2023/5/28 15:12
 * @desciption
 */
public class JacksonAdapter<T> implements JSONAdapter<T> {

    private ObjectMapper mapper = new ObjectMapper();

    {
        // fix jackson Unrecognized field exception
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    @Override
    public T getTarget() {
        return (T) mapper;
    }

    @Override
    public String toJSONString(Object object) {
        for (JsonConvertor convertor : JSONAdapterFactory.getConvertors()) {
            if (convertor.isSerialized(object)) {
                return convertor.convertToString(object);
            }
        }
        try {
            return mapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            throw new JsonAdapterException("Jackson Framework Conversion Exception", e);
        }
    }

    @Override
    public Object toObject(String json) {
        return this.toObject(json, Object.class);
    }

    @Override
    public <K> K toObject(String json, Class<K> clazz) {
        for (JsonConvertor convertor : JSONAdapterFactory.getConvertors()) {
            if (convertor.isDeserialized(json, clazz)) {
                return convertor.convertToObject(json, clazz);
            }
        }
        try {
            return mapper.readValue(json, clazz);
        } catch (JsonProcessingException e) {
            throw new JsonAdapterException("Jackson Framework Conversion Exception", e);
        }
    }

    @Override
    public Object toObject(String json, Type type) {
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            if (parameterizedType.getActualTypeArguments() == null || parameterizedType.getActualTypeArguments().length == 0) {
                return toObject(json, parameterizedType.getRawType());
            } else {
                for (JsonConvertor convertor : JSONAdapterFactory.getConvertors()) {
                    if (convertor.isDeserialized(json, type)) {
                        return convertor.convertToObject(json, type);
                    }
                }
                TypeReference typeReference =  new TypeReference<Object>() {
                    @Override
                    public Type getType() {
                        return type;
                    }
                };
                try {
                    return mapper.readValue(json, typeReference);
                } catch (JsonProcessingException e) {
                    throw new JsonAdapterException("Jackson Framework Conversion Exception", e);
                }
            }
        } else if (type instanceof Class) {
            return toObject(json, (Class) type);
        }
        return null;
    }
}
